package org.tri.persistence.search;

import java.util.List;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.tri.entity.AbstractAnimal;
import org.tri.entity.Establecimiento;
import org.tri.entity.Productor;

/**
 * La clase {@code AbstractBusquedaAnimal} representa la base de la 
 * jerarquia de buscadores de animales.
 * @author kiira
 * @version 1.0, Nov 21, 2011
 */
public abstract class AbstractBusquedaAnimal<K extends AbstractAnimal>
        extends Busqueda<K> {

    /**
     * Inicializa la busqueda.
     * @param clase clase de la entidad a buscar.
     */
    public AbstractBusquedaAnimal( Class<K> clase ) {
        super( clase );

    }//end constructor

    /**
     * Restringe la busqueda a partir de una caravana.
     * Filtra todas los animales cuya caravana no contengan la
     * {@code String} indicada en alguna parte de su caravana.
     * @param caravana caravana exacta o porción de caravana
     * por la cual se desea filtrar.
     */
    public void porCaravana( String caravana ) {
        //creamos y agregamos la restriccion
        Criterion restriccionCaravana = Restrictions.like( "caravana",
                                                           String.format( "%%%s%%",
                                                                          caravana ) );

        agregarCriterio( restriccionCaravana );

    }//end método porCaravana

    /**
     * Restringe la busqueda a los animales cuya caravana
     * se encuentre dentro de un rango de caravanas.
     * @param caravanaInicial caravana inicial del rango.
     * @param caravanaFinal caravana final del rango.
     */
    public void porCaravanasEnRango( String caravanaInicial, String caravanaFinal ) {
        //creamos y agregamos la restriccion
        Criterion restriccionCaravana = Restrictions.between( "caravana", 
                                                              caravanaInicial,
                                                              caravanaFinal );

        agregarCriterio( restriccionCaravana );

    }//end método porCaravanasEnRango
    
    public void porCaravanaEn( List<String> caravanas ) {
        //creamos y agregamos la restriccion
        Criterion restriccionCaravana = Restrictions.in( "caravana", caravanas );

        agregarCriterio( restriccionCaravana );
        
    }

    /**
     * Restringe la busqueda a animales vendidos o no.
     * @param vendido bandera para indicar si se debe filtrar
     * por vendidos o por no vendidos:
     * <li>true - filtra por animales vendidos.
     * <li>false - filtra por animales NO vendidos.
     */
    public void porVendido( boolean vendido ) {
        //creamos y agregamos la restriccion
        Criterion restriccionVendido;

        if ( vendido )
            restriccionVendido = Restrictions.isNotNull( "venta" );
        else
            restriccionVendido = Restrictions.isNull( "venta" );

        agregarCriterio( restriccionVendido );

    }//end método porVendido

    /**
     * Restringe la busqueda a animales vivos o muertos.
     * @param viva <li>true restringe la busqueda a animales vivos.
     * <li>false restringe la busqueda a animales muertos.
     */
    public void porViva( boolean viva ) {
        //creamos y agregamos la restriccion
        Criterion restriccionViva = Restrictions.eq( "viva", viva );        

        agregarCriterio( restriccionViva );
        
    }//end método porViva
    
    /**
     * Restringe la busqueda a animales de un establecimiento específico.
     * @param establecimiento establecimiento a partir del cual se
     * desea filtrar la busqueda.
     */
    public void porEstablecimiento( Establecimiento establecimiento ) {
        //craemos un alias para la compra
        crearAlias( "compra", "comp" );

        //creamos y agregamos la restriccion del establecimiento
        Criterion restriccionEstablecimiento = Restrictions.eq( 
                "comp.establecimiento", establecimiento );

        agregarCriterio( restriccionEstablecimiento );

    }//end método porEstablecimiento

    /**
     * Restringe la busqueda a un productor específico.
     * @param productor productor por el cual filtrar.
     * @param propiedad propiedad a través de la cual se obtiene el 
     * establecimiento para luego restringir el productor.
     */
    protected void porProductor( Productor productor, String propiedad ) {
        //creamos una subcriteria para la compra
        DetachedCriteria subCriteria = obtenerSubCriteria( propiedad );

        //creamos el alias del establecimiento
        subCriteria.createAlias( "establecimiento", "est" );

        //creamos y agregamos la restriccion del productor
        Criterion restriccionProductor = Restrictions.eq( "est.productor", 
                                                          productor );

        subCriteria.add( restriccionProductor );

    }//end método porProductor

}//end clase AbstractBusquedaAnimal

